﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Collections;

namespace Eventable
{
    public class RulesArgs
    {
        /// <summary>
        /// Упаковка значений для события "изменение значения"
        /// </summary>
        /// <param name="oldValue">Старое значение</param>
        /// <param name="newValue">Новое значение</param>
        /// <returns></returns>
        public static object[] ForChangeValue(object oldValue, object newValue)
        {
            return new object[] { oldValue, newValue };
        }

        public static object[] SelectOldNewValue<Tin, Tout>(object[] args, Func<Tin, Tout> funcSelect)
        {
            return new object[] { funcSelect((Tin)args[0]), funcSelect((Tin)args[1]) };
        }

        #region Data extraction from event arguments
        public static EventParamSelector<T> NewValueRef<T>()
            where T : class
        {
            return (sender, evName, args) => args[1] as T;
        }

        public static EventParamSelector<T> OldValueRef<T>()
            where T : class
        {
            return (sender, evName, args) => args[0] as T;
        }

        public static EventParamSelector<T> NewValued<T>()
        {
            return (sender, evName, args) => (T)args[1];
        }

        public static object[] SelectArgs<Tin, Tout>(object[] args, Func<Tin, Tout> selectFunc)
        {
            return args.Cast<Tin>().Select(s => selectFunc(s)).Cast<object>().ToArray();
        }

        public static T NewValuedGet<T>(object sender, string evName, params object[] args)
        {
            return (T)args[1];
        }

        public static T NewValuedGet<T>(object[] args)
        {
            return (T)args[1];
        }

        public static T NewRefGet<T>(object[] args)
            where T : class
        {
            return args[1] as T;
        }

        public static T OldValuedGet<T>(object sender, string evName, params object[] args)
        {
            return (T)args[0];
        }

        public static T OldValuedGet<T>(object[] args)
        {
            return (T)args[0];
        }

        public static T OldRefGet<T>(object[] args)
            where T : class
        {
            return args[0] as T;
        }

        public static EventParamSelector<T> OldValued<T>()
        {
            return (sender, evName, args) => (T)args[0];
        }

        public struct Collection
        {
            public static object[] ForChange<T>(ICollection<T> coll, IEnumerable<T> addValue, IEnumerable<T> removeValue)
            {
                return new object[] { coll, addValue, removeValue };
            }

            public static ICollection<T> Get<T>(object[] args)
            {
                if (args != null && args.Length >= 1)
                    return (args[0] as ICollection<T>) ?? new T[0];
                else
                    return new T[0];
            }

            public static IEnumerable<T> GetAdd<T>(object[] args)
            {
                if (args !=null && args.Length >= 2)
                    return (args[1] as IEnumerable<T>) ?? new T[0];
                else
                    return new T[0];
            }

            public static IEnumerable<T> GetRemove<T>(object[] args)
            {
                if (args !=null && args.Length>=3)
                    return (args[2] as IEnumerable<T>) ?? new T[0];
                else
                    return new T[0];
            }
        }

        #endregion
    }
}
